<template>
  <div class="map-chart-wrap" v-if="showChart">
    <div class="mapping-tit">{{ mainTitle }} <el-button type="text" @click="openFullscreen">放大</el-button> </div>
    <div class="page-wid" ref="panelWrapper" :style="{aspectRatio,'z-index':1}">
      <div :style="panelSty" class="canvas-wrap">
        <canvas ref="panelCanvasBg" class="fabric-panel"></canvas>
      </div>
    </div>
    <PanelPopover
        :info="popoverInfo"
        :position="popoverPosition"
        :visible.sync="popoverVisible"
        :defectType="defectType"
    />
    <!-- 放大 -->
    <el-dialog
        :visible.sync="fullscreenVisible"
        fullscreen
        title="🔍 滚轮滚动以缩放画布，按住 Alt 键拖动可平移查看画布任意位置"
        :modal-append-to-body="false"
        @opened="onFullOpen"
        @closed="destroyFullCanvas"
    >
      <div class="fullscreen-canvas-wrap" ref="fullscreenCanvasWrap"  :style="{aspectRatio,'z-index':1}">
        <PanelPopover
            :info="popoverInfo"
            :position="popoverPosition"
            :visible.sync="popoverVisible"
            :defectType="defectType"
        />
        <canvas ref="fullscreenCanvas" class="full-canvas"></canvas>
      </div>
    </el-dialog>
  </div>
</template>
<script>

import {maxBy} from 'lodash'
import {fabric} from "fabric"
import PanelPopover from "./PanelPopover.vue"
export default {
  components:{
    PanelPopover
  },

  props: {
    defectType: {
      type: String,
      default: 'RATIO',
    },
    tableTitle: {
      type: String,
      default: ''
    },
  },
  data() {
    return {
      fullscreenVisible:false,
      fullCanvas: null, // 全屏画布实例
      showChart: true,
      loading: false,
      PanelLayout: {
        totalHeight: 0,
        totalWidth: 0,
        qpanelInfos: [],
      },
      mainTitle: "",
      popoverVisible: false,
      popoverPosition: {x: 0, y: 0},
      hoverPanelId: '',
      hoverRatio: 0,
      wrapWidth: 0,
      wrapHeight: 0,
      popoverInfo: {
        ratio: "",
        qty: "",
        mmt: ""
      },
      canvas: null,
    }
  },
  computed: {
    panelSty() {
      return {
        width: this.wrapWidth + "px",
        height: this.wrapHeight + "px",
      }
    },
    clientWidth() {
      return this.$refs.mypanel ? this.$refs.mypanel.clientWidth : 0;
    },
    aspectRatio() {
      let {totalWidth: w, totalHeight: h} = this.PanelLayout
      return w / h
    }
  },
  mounted() {

    this.initData()
    window.addEventListener('resize', this.onChartResize)
  },
  methods: {
    openFullscreen() {
      this.fullscreenVisible = true
    },
    onFullOpen() {
      this.$nextTick(() => {
        const fullEl = this.$refs.fullscreenCanvas
        const fullCanvasWrapWidth = this.$refs.fullscreenCanvasWrap.clientWidth
        console.log('放大后宽度',fullCanvasWrapWidth)
        // 创建新的 Fabric 实例,默认放大个2倍
        this.fullCanvas = new fabric.Canvas(fullEl, {
          width:fullCanvasWrapWidth,
          height:fullCanvasWrapWidth*this.aspectRatio,
          backgroundColor: '#fff',
          enableRetinaScaling: false,
        })
        // 从原画布复制 JSON
        const json = this.canvas.toJSON(['selectable', 'evented','panelId', 'ratio', 'qty', 'mmt', 'mmtAll', 'fillPer','isPanelGroup'])
        this.fullCanvas.loadFromJSON(json, () => {
          this.fullCanvas.getObjects().forEach(obj => {
            if (obj.type === 'group' && obj.isPanelGroup) {
              this.bindGroupEvent(obj)
            }
          })
          let defaultZoom= this.$refs.fullscreenCanvasWrap.clientWidth/this.wrapWidth
          this.fullCanvas.setZoom(defaultZoom)
          const vpt = this.canvas.viewportTransform.slice()
          /* viewportTransform 是一个 6 元素的数组 [ a, b, c, d, e, f ]
               a:scaleX（X 方向缩放）  b:Y 斜切（一般是 0）   c:X 斜切（一般是 0）
               d:scaleY（Y 方向缩放）  e:平移 X               f:平移 Y
          */
          vpt[0] *= defaultZoom
          vpt[3] *= defaultZoom
          vpt[4] *= defaultZoom
          vpt[5] *= defaultZoom
          this.fullCanvas.setViewportTransform(vpt)
          //添加放大缩放事件
          this.fullCanvas.on('mouse:wheel', (opt) => {
            opt.e.preventDefault(); // 阻止浏览器默认滚动
            opt.e.stopPropagation();
            const delta = opt.e.deltaY;
            let zoom = this.fullCanvas.getZoom();
            // 每滚一次缩放 10%
            zoom *= delta > 0 ? 0.9 : 1.1;
            // 限制最大最小比例
            zoom = Math.max(0.5, Math.min(100, zoom));
            this.fullCanvas.zoomToPoint(
                { x: opt.e.offsetX, y: opt.e.offsetY },
                zoom
            );
            this.fullCanvas.renderAll();
          })
          // 鼠标按下开始拖动
          this.fullCanvas.on('mouse:down', (opt) => {
            const evt = opt.e
            if (evt.altKey) { // 可按住 Alt 或其他条件启用拖动画布
              this.isPanning = true
              this.lastPosX = evt.clientX
              this.lastPosY = evt.clientY
            }
          })
          // 鼠标移动
          this.fullCanvas.on('mouse:move', (opt) => {
            if (!this.isPanning) return
            const e = opt.e
            const vpt = this.fullCanvas.viewportTransform
            vpt[4] += e.clientX - this.lastPosX
            vpt[5] += e.clientY - this.lastPosY
            this.fullCanvas.requestRenderAll()
            this.lastPosX = e.clientX
            this.lastPosY = e.clientY
          })
          // 鼠标释放
          this.fullCanvas.on('mouse:up', () => {
            this.isPanning = false
          })
          this.fullCanvas.requestRenderAll()

        })
      })
    },

    /** 销毁全屏画布 */
    destroyFullCanvas() {
      if (this.fullCanvas) {
        this.fullCanvas.dispose()
        this.fullCanvas = null
      }
    },
    setLayout(myPanel, PanelLayout) {
      if (!myPanel) {
        return
      }
      const width = myPanel.clientWidth
      const height = myPanel.clientHeight
      this.wrapWidth = width
      this.wrapHeight = height


      let {totalWidth, totalHeight, qpanelInfos} = PanelLayout
      let scale = width / totalWidth//画布数据和散点图内容区域比例
      this.wrapWidth = totalWidth * scale
      this.wrapHeight = totalHeight * scale
      if (!this.canvas) {
        this.canvas = new fabric.Canvas(this.$refs.panelCanvasBg, {
          selection: false,
          enableRetinaScaling:false,
          width: this.wrapWidth,
          height: this.wrapHeight,
          skipTargetFind:false,
          hoverCursor: 'pointer',
          renderOnAddRemove:false
        })
      }
      this.canvas.clear()
      let objectsToAdd = []
      for (let it of qpanelInfos) {
        for (let it2 of it.panelInfos) {
          objectsToAdd.push(this.setRectTxtGroup(it2, totalWidth, totalHeight))
        }
        objectsToAdd.push(this.setRectTxtGroup(it, totalWidth, totalHeight, true))
      }
      this.canvas.add(...objectsToAdd)
      this.canvas.setZoom(scale)
      //  this.canvas.calcOffset()
      this.canvas.requestRenderAll()
    },
    setRectTxtGroup(it, totalWidth, totalHeight, isQ = false) {//大Q降低不透明度，扩大字体100px
      let {topLeftX, topLeftY, bottomRightX, bottomRightY, panelId} = it
      let width = Math.abs(bottomRightX - topLeftX)
      let height = Math.abs(bottomRightY - topLeftY)

      // 1. 限制字体大小的逻辑
      const minDim = Math.min(width, height);
      let calculatedFontSize = minDim*0.8;//为Q时，缩放0.8倍，为panel时，缩小一半
      let scaleList = [
        {len: 3, scale: 0.8},
        {len: 4, scale: 0.7},
        {len: 5, scale: 0.6},
        {len: 6, scale: 0.5},
        {len: 7, scale: 0.4},
        {len: 8, scale: 0.3},
        {len: 9, scale: 0.3},
        {len: 10, scale: 0.3}]//最新0.5，再小了就看不清
      if (panelId.length > 2) {
        let scaleItem = scaleList.find(item => item.len === panelId.length)
        calculatedFontSize = calculatedFontSize * scaleItem.scale
      }
      if (isQ) {
        let rect = new fabric.Rect({
          width,
          height,
          fill: '#fff',
          strokeWidth: 0,
          originX: 'center',
          originY: 'center',
        })
        let text = new fabric.Text(panelId, {
          fontSize: calculatedFontSize*0.8,
          fill: '#000',
          originX: 'center',
          originY: 'center',
        })
        return new fabric.Group([rect, text], {
          left: totalWidth / 2 + topLeftX,
          top: totalHeight / 2 - topLeftY,
          originX: 'left',
          originY: 'top',
          opacity: 0.2,
          selectable: false, // 不允许选中/拖动
          evented: false,     // 可以响应鼠标事件
        })
      } else {
        let rect = new fabric.Rect({
          width,
          height,
          fill: '#fff',
          stroke: '#ccc',        // 边框颜色
          strokeWidth: 1,
          originX: 'center',
          originY: 'center',
        })
// 用于按比例填充的矩形（从左向右填充）
        const rectFill = new fabric.Rect({
          width: width * it.fillPer, // 按比例设置宽度
          height: height,
          fill: '#B7DAFE',
          originX: 'left',         // 从左侧开始
          originY: 'center',
          left: -width / 2,        // 对齐到背景矩形左边（因为背景的 originX=center）
        });
        const ratioTxt = new fabric.Text(it.ratio + '%', {
          fontSize: 12,
          fill: '#000',
          originX: 'center',
          originY: 'center',
        })
        const text = new fabric.Text(panelId, {
          fontSize: 12,
          fill: '#000',
          originX: 'left',   // 左对齐
          originY: 'top',    // 顶部对齐
          left: -width / 2 + 2,  // 从矩形左上角稍微内缩2px
          top: -height / 2 + 2,
        })
        let group = new fabric.Group([rect, rectFill, text, ratioTxt], {
          left: totalWidth / 2 + topLeftX,
          top: totalHeight / 2 - topLeftY,
          originX: 'left',
          originY: 'top',
          selectable: false, // 不允许选中/拖动
          evented: true,     // 可以响应鼠标事件
          hoverCursor: 'pointer', // 鼠标样式
        })
        //把业务数据挂载到group上，给Popover使用
        group.set({
          isPanelGroup:true,
          panelId: panelId,
          ratio: it.ratio,
          qty: it.qty,
          mmt: it.mmt,
          mmtAll: it.mmtAll,
          fillPer: it.fillPer,
        })
        // 绑定事件
        this.bindGroupEvent(group)
        return group
      }
    },
    bindGroupEvent(group){
      group.on('mouseover', (opt) => {
        const { e, target } = opt
        this.popoverVisible = true
        this.hoverPanelId = target.panelId
        this.hoverRatio = target.ratio * 100
        for (let attr in this.popoverInfo) {
          this.popoverInfo[attr] = target[attr]
        }
        // 用视口坐标
        const mouseX = e.layerX
        const mouseY = e.layerY


        this.popoverPosition = {
          x: mouseX + 40,
          y: mouseY + 40
        }
      })
      group.on('mouseout', (opt) => {
        this.popoverVisible = false
      })
    },
    defectRatioText(panelTable) {
      let mappingTotal = {
        qty: 0,
        mmt: 0
      }
      mappingTotal.qty = panelTable.reduce((acc, item) => {
        return acc + item.qty
      }, 0)
      mappingTotal.mmt = panelTable.reduce((acc, item) => {
        return acc + item.mmt
      }, 0)
      let title = ""
      if (this.isArray) {
      } else {
        title = `${(mappingTotal.qty / mappingTotal.mmt * 100).toFixed(2)}%（${mappingTotal.qty}/${mappingTotal.mmt}）`
      }
      if (this.defectType === "POINT") {
        title = this.tableTitle + "不良Total 点位数：" + mappingTotal.qty
      } else {
        title = this.tableTitle + "不良Total Ratio：" + title
      }
      this.mainTitle = title
    },
    onChartResize() {
      this.$nextTick(() => {
        this.setLayout(this.$refs.panelWrapper, this.PanelLayout)
      })
    },
    fillDataInPanel(panelTable, layoutData) {
      console.log('原始数据',panelTable, layoutData)
      let key = this.defectType === "RATIO" ? 'ratio' : 'qty'
      let maxValue = maxBy(panelTable, item => parseFloat(item[key]))[key]
      console.log('最大值',maxValue)
      let finalPanelData = panelTable.map(item => ({
        ...item,
        fillPer: parseFloat((item[key] / maxValue).toFixed(2))
      }))

      layoutData.qpanelInfos.forEach(qPanel => {
        qPanel.panelInfos.forEach(panel => {
          //finalPanelData里的x和qPanel的id一样，y排除第一位后，和panel的id一样
          let match=finalPanelData.find(info => qPanel.panelId===info.x &&panel.panelId===info.y.slice(1))
          if (match) {
            Object.assign(panel, {
              qty: match.qty,
              mmt: match.mmt,
              mmtAll: match.mmtAll,
              ratio: match.ratio,
              fillPer: match.fillPer
            })
          }
        })
      })
      console.log('09090',layoutData)

      //
      // finalPanelData.forEach(item => {
      //   let qPanelId = item.y.slice(1)//y值第一位对于qPanel ID
      //   let tempFill=layoutData.qpanelInfos.find(panel => panel.panelId === qPanelId)
      //
      //   if(tempFill){
      //     tempFill.panelInfos.forEach(panel => {
      //       if(item.y.slice(1)===panel.panelId){
      //         Object.assign(panel, {
      //           qty: match.qty,
      //           mmt: match.mmt,
      //           mmtAll: match.mmtAll,
      //           ratio: match.ratio,
      //           fillPer: match.fillPer
      //         })
      //       }
      //     })
      //   }
      //
      //   // let panel = layoutData.qpanelInfos.find(panel => panel.panelId === panelId)
      //   // if (panel) {
      //   //   panel.panelInfos.push(item)
      //   // }
      // })


      // const fillMap = new Map(finalPanel.map(i => [i.y.slice(1), i]))
      // layoutData.qpanelInfos.forEach(panel => {
      //   panel.panelInfos.forEach(info => {
      //     const match = fillMap.get(info.panelId)
      //     if (match) {
      //       Object.assign(info, {
      //         qty: match.qty,
      //         mmt: match.mmt,
      //         mmtAll: match.mmtAll,
      //         ratio: match.ratio,
      //         fillPer: match.fillPer
      //       })
      //     }
      //   })
      // })
    },
    // fillDataInPanel(panelTable, layoutData) {//把数据填充到panel中，数据y首字母记录了Q-panel，比如AAA，是A下面的AA
    //   let fistKey = Object.keys(panelTable)[0]
    //   let layoutVal = panelTable[fistKey]
    //   let key = this.defectType === "RATIO" ? 'ratio' : 'qty'
    //   let maxValue = maxBy(layoutVal, item => parseFloat(item[key]))[key]
    //   let finalPanel = layoutVal.map(item => ({
    //     ...item,
    //     fillPer: parseFloat((item[key] / maxValue).toFixed(2))
    //   }))
    //   const fillMap = new Map(finalPanel.map(i => [i.y.slice(1), i]))
    //   layoutData.qpanelInfos.forEach(panel => {
    //     panel.panelInfos.forEach(info => {
    //       const match = fillMap.get(info.panelId)
    //       if (match) {
    //         Object.assign(info, {
    //           qty: match.qty,
    //           mmt: match.mmt,
    //           mmtAll: match.mmtAll,
    //           ratio: match.ratio,
    //           fillPer: match.fillPer
    //         })
    //       }
    //     })
    //   })
    // },
    async initData() {
      this.loading = true
      let {data: PanelLayout} = await fetch(`http://localhost:9000/alarm/mapLayout`).then(r => r.json())
      console.log(1111111111,PanelLayout)
      let currentPanel=PanelLayout.records[0]
      Object.assign(this.PanelLayout, currentPanel)
      // let {data: detailData} = await fetch(`http://localhost:9000/alarm/alarmDetail`).then(r => r.json())
      let {data: panelTableTemp} = await fetch(`http://localhost:9000/alarm/panelTable`).then(r => r.json())
      let panelData = panelTableTemp[Object.keys(panelTableTemp)[0]]
      this.fillDataInPanel(panelData, this.PanelLayout)
      this.defectRatioText(panelData)
      this.showChart = true
      this.loading = false
      this.$nextTick(() => {
        this.setLayout(this.$refs.panelWrapper, this.PanelLayout)
      })
    },
  }
}
</script>
<style lang="stylus" scoped>
.mapping-tit {
  color: rgb(51, 51, 51);
  margin: 0 auto 5px;
  text-overflow: ellipsis;
  white-space: nowrap;
  overflow: hidden;
  font-size: 14px;
  text-align: left;
}

.map-chart-wrap {
  width: 100%;
  position: relative;
  padding-bottom: 16px;
  .page-wid {
    width: 100%;
  }
}

.fabric-panel {
  position absolute;
  left 0;
  top 0;
  width: 100%;
  display: block;
}

.canvas-wrap{
  width: 100%;
  position relative;
  left: 0;
  top: 0;
  overflow: hidden;
  border: 1px solid #ccc;
}

.fullscreen-canvas-wrap{
  border: 1px solid #ccc;
}
</style>